package com.whfc.fuum.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.enums.SysDeptType;
import com.whfc.common.enums.SysRulePlatform;
import com.whfc.common.enums.SysUserType;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.PageUtil;
import com.whfc.entity.dto.Apply.rep.InstitutionRep;
import com.whfc.entity.dto.Apply.req.UserDeptDTO;
import com.whfc.fuum.dao.*;
import com.whfc.fuum.dto.*;
import com.whfc.fuum.entity.*;
import com.whfc.fuum.manager.SysDeptManager;
import com.whfc.fuum.param.*;
import com.whfc.fuum.redis.SysDeptRedisDao;
import com.whfc.fuum.redis.SysUserRedisDao;
import com.whfc.fuum.service.SysDeptService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @author: xugcheng
 * @version: 1.0
 * @date: 2019/10/15 12:00
 */
@DubboService(interfaceClass = SysDeptService.class, version = "1.0.0")
public class SysDeptServiceImpl implements SysDeptService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SysDeptUserMapper sysDeptUserMapper;

    @Autowired
    private SysRuleMapper sysRuleMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysDeptManager sysDeptManager;

    @Autowired
    private SysUserRedisDao sysUserRedisDao;

    @Autowired
    private SysDeptRedisDao sysDeptRedisDao;

    @Autowired
    private SysDeptExtMapper sysDeptExtMapper;

    @Autowired
    private SysEmpUserMapper sysEmpUserMapper;

    @Override
    public SysDeptDTO getSysDeptDTO(Integer deptId) {
        logger.info("获取组织机构信息服务,deptId:{}", deptId);
        SysDept dept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (dept == null) {
            return null;
        }
        SysDeptDTO sysDeptDTO = new SysDeptDTO();
        BeanUtils.copyProperties(dept, sysDeptDTO);
        return sysDeptDTO;
    }

    @Override
    public SysDeptDTO getDeptDTOById(Integer deptId) throws BizException {
        logger.info("获取机构信息,deptId:{}", deptId);
        return sysDeptManager.getDeptDTOById(deptId);
    }

    @Override
    public String getDeptName(Integer deptId) {
        logger.info("通过组织机构id获取名称服务,deptId:{}", deptId);
        String name = null;
        if (deptId != null) {
            name = sysDeptMapper.selectDeptNameById(deptId);
        }
        return name;
    }

    @Override
    public Map<Integer, String> getDeptNameMap(List<Integer> deptIds) throws BizException {
        logger.info("批量查找组织机构服务,deptIds:{}", deptIds);
        List<SysDeptDTO> list = sysDeptMapper.selectByIds(deptIds);
        Map<Integer, String> map = new HashMap<>();
        for (SysDeptDTO sysDeptDTO : list) {
            Integer id = sysDeptDTO.getId();
            String name = sysDeptDTO.getName();
            map.putIfAbsent(id, name);
        }
        return map;
    }

    @Override
    public String getDeptNameById(Integer deptId) throws BizException {
        logger.info("获取组织机构名称,deptId:{}", deptId);
        return sysDeptManager.getDeptNameById(deptId);
    }


    @Override
    public List<SysDeptDTO> getAllProjectList() {
        logger.info("获取所有项目服务");
        return sysDeptMapper.selectAllProject();
    }

    @Override
    public List<SysDeptDTO> getDeptTree(SysUser sysUser, Integer deptId, String keyword) throws BizException {
        logger.info("获取组织机构树,user:{},deptId{},keyword:{}", sysUser.getNickname(), deptId, keyword);
        List<SysDeptDTO> deptList;
        if (deptId != null) {
            deptList = sysDeptManager.getDescendantDeptListById(deptId, keyword);
        } else {
            Integer userType = sysUser.getType();
            if (SysUserType.INNER.getValue().equals(userType)) {
                //内部账号-加载所有的组织机构
                Integer rootDeptId = 0;
                deptList = sysDeptManager.getDescendantDeptListById(rootDeptId, keyword);
            } else {
                //客户账号/体验账号-加载单个客户的组织机构
                deptList = sysDeptUserMapper.selectDescendantDeptList(sysUser.getId(), keyword);
            }
        }
        if (deptList == null || deptList.isEmpty()) {
            return Collections.emptyList();
        }
        return sysDeptManager.buildDeptTree(deptList);
    }

    @Override
    public List<SysDeptDTO> getDeptListByRuleCode(SysUser sysUser, Integer deptId, String ruleCode, SysRulePlatform platform) throws BizException {
        logger.info("根据组织机构获取用户可以查看的组织机构列表,user:{},deptId:{},ruleCode:{},platform:{}",
                sysUser.getNickname(), deptId, ruleCode, platform.getValue());
        Integer userType = sysUser.getType();
        //验证功能权限编码.
        SysRule rule = sysRuleMapper.selectByCode(ruleCode, platform.getValue());
        if (rule == null) {
            return Collections.emptyList();
        }

        //内部账号-加载所有的组织机构
        if (SysUserType.INNER.getValue().equals(userType)) {
            Integer rootDeptId = deptId != null ? deptId : 0;
            List<SysDeptDTO> deptList = sysDeptManager.getDescendantDeptListById(rootDeptId, null);
            for (SysDeptDTO deptDTO : deptList) {
                deptDTO.setAuthorized(true);
            }
            return deptList;
        }
        //客户账号/体验账号-加载单个客户的组织机构
        else {
            List<SysDeptDTO> deptList;
            if (deptId != null) {
                //获取指定组织机构下面及下面的所有组织机构
                deptList = sysDeptManager.getDescendantDeptListById(deptId, null);
            } else {
                //获取用户的所有组织机构
                deptList = sysDeptUserMapper.selectDescendantDeptList(sysUser.getId(), null);
            }
            List<SysDeptDTO> authorizedDeptList = sysDeptMapper.selectDeptListByUserIdAndRuleId(sysUser.getId(), rule.getId());
            for (SysDeptDTO deptDTO : deptList) {
                deptDTO.setAuthorized(authorizedDeptList.contains(deptDTO));
            }
            return deptList;
        }
    }

    @Override
    public PageData<SysDeptDTO> list(AppDeptListParam request) throws BizException {
        logger.info("获取组织机构列表, request:{}", JSON.toJSONString(request));
        Integer depId = request.getDeptId();
        List<Integer> deptIdList = sysDeptMapper.selectChildDeptIdList(depId);

        request.setDeptIds(deptIdList);
        Integer pageNum = request.getPageNum();
        Integer pageSize = request.getPageSize();

        PageHelper.startPage(pageNum, pageSize);
        List<SysDeptDTO> list = sysDeptMapper.selectByParam(request);
        PageHelper.clearPage();

        return PageUtil.pageData(PageInfo.of(list));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysDeptDTO addDept(SysDeptAdd deptAdd) throws BizException {
        logger.info("添加组织机构, request:{}", JSON.toJSONString(deptAdd));
        SysDept sysDept = sysDeptManager.addDept(deptAdd);
        SysDeptDTO sysDeptDTO = new SysDeptDTO();
        BeanUtils.copyProperties(sysDept, sysDeptDTO);
        return sysDeptDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editDept(SysDeptEdit deptEdit) throws BizException {
        logger.info("编辑组织机构,request:{}", JSON.toJSONString(deptEdit));
        sysDeptManager.editDept(deptEdit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delDept(Integer deptId) throws BizException {
        logger.info("删除组织机构,deptId:{}", deptId);
        sysDeptManager.delDept(deptId);
    }

    @Override
    public void indexMove(SysDeptMoveIndex request) {
        logger.info("移动组织机构索引，request:{}", JSON.toJSONString(request));
        List<Integer> deptIds = request.getDeptIds();
        if (deptIds == null || deptIds.size() != 2) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "参数错误.");
        }
        SysDept dept = sysDeptMapper.selectByPrimaryKey(deptIds.get(0));
        SysDept dept1 = sysDeptMapper.selectByPrimaryKey(deptIds.get(1));
        if (dept == null || dept1 == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "组织机构不存在.");
        }
        if (!dept.getPid().equals(dept1.getPid())) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "移动位置必须是在同一个节点下.");
        }
        Integer index = dept.getIndex();
        Integer index1 = dept1.getIndex();
        dept.setIndex(index1);
        sysDeptMapper.updateByPrimaryKeySelective(dept);
        dept1.setIndex(index);
        sysDeptMapper.updateByPrimaryKeySelective(dept1);
    }

    @Override
    public List<Integer> getDescendantDeptIdList(Integer id) {
        logger.info("获取子项目服务,deptId:{}", id);
        return sysDeptMapper.selectDescendantDeptIdList(id);
    }

    @Override
    public List<SysDeptDTO> getDescendantDeptListById(Integer deptId, String keyword) throws BizException {
        return sysDeptManager.getDescendantDeptListById(deptId, keyword);
    }

    @Override
    public List<SysDeptDTO> getDescendantDeptListById(Integer deptId) throws BizException {
        logger.info("查询所有子孙节点,deptId:{}", deptId);
        return sysDeptManager.getDescendantDeptListById(deptId, null);
    }

    @Override
    public List<SysDeptDTO> getProjectListByUserId(Integer userId) throws BizException {
        logger.info("查询用户关联的项目,userId:{}", userId);
        return sysDeptMapper.selectProjectListByUserId(userId);
    }

    @Override
    public SysDeptUser getDeptUserByUserId(Integer userId, Integer deptId) throws BizException {
        logger.info("查询用户绑定组织机构,userId:{},deptId:{}", userId, deptId);
        return sysDeptManager.getDeptUserByUserId(userId, deptId);
    }

    @Override
    public void importUser(SysDeptUserImport request) throws BizException {
        logger.info("批量导入用户，request:{}", JSON.toJSONString(request));
        Integer deptId = request.getDeptId();
        List<Integer> userIds = request.getUserIds();
        List<Integer> roleIds = request.getRoleIds();
        for (Integer userId : userIds) {
            //绑定 用户 组织机构
            sysDeptUserMapper.insertDeptUser(deptId, userId);
            //组织机构用户角色绑定
            sysUserRoleMapper.batchInsertUserRole(deptId, userId, roleIds);
        }
        //删除用户组织机构ID列表缓存
        sysUserRedisDao.deleteUserDeptIds(userIds);
        //删除用户权限缓存
        sysUserRedisDao.deleteUserRules(userIds);
    }

    @Override
    public void removeUser(Integer deptId, Integer userId) throws BizException {
        logger.info("移除组织机构用户,deptId:{},userId:{}", deptId, userId);
        //逻辑删除用户与组织机构的关系
        sysDeptUserMapper.logicDel(deptId, userId);
        //删除用户组织机构角色的关系
        sysUserRoleMapper.delUserRoles(deptId, userId);

        //删除用户组织机构ID列表缓存
        sysUserRedisDao.deleteUserDeptIds(userId);
        //删除用户权限缓存
        sysUserRedisDao.deleteUserRules(userId);

    }

    @Override
    public PageData<SysUserDTO> getImportEmpUserList(SysUser sysUser, Integer deptId, Integer pageNum, Integer pageSize, String keyword) throws BizException {
        logger.info("获取可以导入的部门人员列表，user:{},deptId:{},pageNum:{},pageSize:{},keyword:{}", sysUser.getNickname(),
                deptId, pageNum, pageSize, keyword);
        PageData<SysUserDTO> pageData = this.getImportUserList(sysUser, deptId, pageNum, pageSize, keyword);
        if (pageData.getList() != null){
            List<Integer> sysUserIdList = pageData.getList().stream().map(SysUserDTO::getId).collect(Collectors.toList());
            if (sysUserIdList.size() == 0){
                return pageData;
            }
            List<SysEmpUser> sysEmpUsers = sysEmpUserMapper.getEmpUserListExcludeUserId(sysUserIdList);
            List<Integer> invalidSysUserIdList = sysEmpUsers.stream().map(SysEmpUser::getSysUserId).collect(Collectors.toList());
            List<SysUserDTO> validSysUserList = pageData.getList().stream().filter(sysUserDTO -> !invalidSysUserIdList.contains(sysUserDTO.getId())).collect(Collectors.toList());
            pageData.setList(validSysUserList);
        }
        return pageData;
    }
    @Override
    public PageData<SysUserDTO> getImportUserList(SysUser sysUser, Integer deptId, Integer pageNum, Integer pageSize, String keyword) throws BizException {
        logger.info("获取可以导入的人员列表，user:{},deptId:{},pageNum:{},pageSize:{},keyword:{}", sysUser.getNickname(),
                deptId, pageNum, pageSize, keyword);
        Integer type = sysUser.getType();
        //获取当前组织机构的人员ID列表
        List<Integer> userIdList = sysDeptUserMapper.selectUserIdListByDeptId(deptId);
        //获取可导入人员的组织机构ID
        List<Integer> deptIdList = sysDeptUserMapper.selectDeptIdByUserId(sysUser.getId());
        PageHelper.startPage(pageNum, pageSize);
        List<SysUserDTO> list;
        if (SysUserType.INNER.getValue().equals(type)) {
            //内部人员 获取所有人员
            list = sysUserMapper.selectImportUserList(userIdList, keyword);
        } else {
            //客户 获取所在部门的所有人员
            if (deptIdList.isEmpty()) {
                list = Collections.emptyList();
            } else {
                list = sysDeptUserMapper.selectImportUserList(deptIdList, userIdList);
            }
        }
        PageInfo<SysUserDTO> pageInfo = PageInfo.of(list);
        return PageUtil.pageData(pageInfo);
    }

    @Override
    public SysDeptDTO getDeptByPidAndGuid(Integer pid, String guid) throws BizException {
        logger.info("根据PID以及GUID查找组织机构, pid:{}, guid:{}", pid, guid);
        return sysDeptMapper.selectByPidAndGuid(pid, guid);
    }

    @Override
    public Integer getDeptByGuidAndUser(String guid, Integer userId, Integer userType) throws BizException {
        logger.info("根据GUID以及用户ID查找组织机构ID, guid:{}, userId:{}, userType:{}", guid, userId, userType);
        if (StringUtils.isBlank(guid) || userId == null) {
            return null;
        }
        //从缓存中获取组织机构
        SysDeptDTO sysDept = sysDeptRedisDao.getSysDept(guid);
        if (sysDept == null) {
            sysDept = sysDeptMapper.selectByGuid(guid);
            if (sysDept == null) {
                return null;
            }
            sysDeptRedisDao.setSysDept(guid, sysDept);
        }
        //内部用户直接返回
        Integer deptId = sysDept.getId();
        if (SysUserType.INNER.getValue().equals(userType)) {
            return deptId;
        }
        //获取用户的所有组织机构
        List<Integer> deptIds = getDeptIdListByUser(userId, userType);
        logger.info("deptIds:{}", deptIds);
        //排查当前组织机构是否是用户所拥有的组织机构
        if (deptIds != null && !deptIds.isEmpty() && deptIds.contains(deptId)) {
            return deptId;
        } else {
            return null;
        }
    }

    @Override
    public List<Integer> getDeptIdListByUser(Integer userId, Integer userType) throws BizException {
        logger.info("根据用户ID查找组织机构ID列表, userId:{}, userType:{}", userId, userType);
        List<Integer> deptIdList = null;
        if (userId == null || userType == null) {
            return deptIdList;
        }
        deptIdList = sysUserRedisDao.getDeptIds(userId);
        if (deptIdList != null && !deptIdList.isEmpty()) {
            return deptIdList;
        }
        if (SysUserType.INNER.getValue().equals(userType)) {
            //内部账号 获取所有的组织机构ID
            deptIdList = sysDeptMapper.selectAllDeptId();
        } else {
            //客户账号、体验账号 获取用户所在的组织机构及其子孙组织机构ID
            List<SysDeptDTO> deptList = sysDeptUserMapper.selectDescendantDeptList(userId, null);
            logger.info("deptList:{}", deptList);
            deptIdList = deptList.stream().map(SysDeptDTO::getId).collect(Collectors.toList());
        }
        if (deptIdList != null && !deptIdList.isEmpty()) {
            sysUserRedisDao.setDeptIds(userId, deptIdList);
        }
        return deptIdList;
    }

    @Override
    public SysDeptExtraDTO getDeptExtra(Integer deptId) throws BizException {
        logger.info("获取公司扩展信息, deptId:{}", deptId);
        SysDeptExtraDTO deptExtraDTO = new SysDeptExtraDTO();
        //获取组织机构信息
        SysDept sysDept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (sysDept == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "该组织机构不存在");
        }
        //当前不是公司
        if (!SysDeptType.company.getValue().equals(sysDept.getType())) {
            return deptExtraDTO;
        }
        //获取扩展信息
        SysDeptExt sysDeptExt = sysDeptExtMapper.selectByDeptId(deptId);
        if (sysDeptExt == null) {
            return deptExtraDTO;
        }

        //转换json
        SysDeptExtInfoDTO sysDeptExtInfoDTO = JSON.parseObject(sysDeptExt.getExtInfo(), SysDeptExtInfoDTO.class);
        List<String> imgList = new ArrayList<>();
        if (sysDeptExtInfoDTO != null) {
            BeanUtils.copyProperties(sysDeptExtInfoDTO, deptExtraDTO);
            //保存图片信息
            for (AppProjectImgDTO appProjectImgDTO : sysDeptExtInfoDTO.getImgList()) {
                imgList.add(appProjectImgDTO.getImgUrl());
            }
        }

        //保存位置相关信息
        deptExtraDTO.setAddress(sysDeptExt.getAddress());
        deptExtraDTO.setLng(sysDeptExt.getLng());
        deptExtraDTO.setLat(sysDeptExt.getLat());

        deptExtraDTO.setImgList(imgList);
        // 获取安全施工天数
        Date startDate = deptExtraDTO.getStartDate();
        Date endTime = new Date();
        if (startDate == null || startDate.getTime() > endTime.getTime()) {
            deptExtraDTO.setSafeDays(0);
        } else {
            int safeDays = DateUtil.getDaysBettweenDate(startDate, endTime);
            deptExtraDTO.setSafeDays(safeDays);
        }
        return deptExtraDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setDeptExtra(SysDeptExtraParam param) throws BizException {
        logger.info("添加公司扩展信息,param:{}", param);
        Integer deptId = param.getDeptId();
        SysDept sysDept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (sysDept == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "该组织机构不存在");
        }
        if (!SysDeptType.company.getValue().equals(sysDept.getType())) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "只有公司级才可以添加扩展信息");
        }
        SysDeptExt sysDeptExt = sysDeptExtMapper.selectByDeptId(deptId);
        if (sysDeptExt == null) {
            sysDeptExt = new SysDeptExt();
        }
        //保存基本信息
        sysDeptExt.setDeptId(deptId);
        sysDeptExt.setAddress(param.getAddress());
        sysDeptExt.setLng(param.getLng());
        sysDeptExt.setLat(param.getLat());
        SysDeptExtInfoDTO deptExtInfo = new SysDeptExtInfoDTO();
        BeanUtils.copyProperties(param, deptExtInfo);
        //图片处理
        List<AppProjectImgDTO> imgList = new ArrayList<>();
        for (String imgUrl : param.getImgList()) {
            AppProjectImgDTO projectImg = new AppProjectImgDTO();
            projectImg.setImgUrl(imgUrl);
            imgList.add(projectImg);
        }
        deptExtInfo.setImgList(imgList);
        sysDeptExt.setExtInfo(JSON.toJSONString(deptExtInfo));
        if (sysDeptExt.getId() == null) {
            //新建
            sysDeptExtMapper.insertSelective(sysDeptExt);
        } else {
            //更新
            sysDeptExtMapper.updateByPrimaryKeySelective(sysDeptExt);
        }
    }

    @Override
    public List<SysDeptDTO> getDeptByIds(List<Integer> deptIds) {
        return sysDeptMapper.selectByIds(deptIds);
    }

    @Override
    public List<InstitutionRep> getUnit(Integer deptId) {
        return sysDeptMapper.getUnit(deptId);
    }

    @Override
    public List<UserDeptDTO> queryMessage(Integer deptId) {

        return sysDeptMapper.queryMessage(deptId);
    }

    @Override
    public SysDeptDTO selectSysDeptById(Integer deptId) {
        return sysDeptMapper.selectById(deptId);
    }

    @Override
    public String selectDeptIdById(Integer id) {
        return sysDeptMapper.selectDeptIdById(id);
    }
}
